package com.ld.shieldsb.dao.model;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.ObjectUtils;

import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType;
import com.ld.shieldsb.annotation.field.link.Many2Many;
import com.ld.shieldsb.annotation.util.AnnotationUtil;
import com.ld.shieldsb.annotation.util.TableNameUtil;
import com.ld.shieldsb.common.core.collections.ListUtils;
import com.ld.shieldsb.common.core.reflect.FunctionUtil;
import com.ld.shieldsb.common.core.reflect.FunctionUtil.Property;
import com.ld.shieldsb.common.core.util.StringUtils;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Data
@Slf4j
public class QueryModel implements Cloneable {

    protected String selectFields = "*";
    protected String condition = "";// 查询条件
    protected String order = "";// 排序条件

    protected Boolean queryLink = false; // 查询级联对象
    protected List<Property<?, ?>> queryLinkFields = null; // 查询哪些级联对象，如果queryLink为true此项不设置默认查询model中配置了@Link注解的

    protected List<Object> params = new ArrayList<>();

    protected List<Condition> cnds = new ArrayList<>(); // 条件
    protected List<Order> orders = new ArrayList<>(); // 排序
    protected List<String> groupBys = new ArrayList<>(); // 分组，待测试

    protected String joinTableAlias = null;// 用于join查询用,表别名
    protected JoinType joinType = null; // join类型
    protected Boolean joinMust = false; // 是否一定使用join查询，默认false，则连表条件为空时不使用join语句，如果为true则一定使用

    public QueryModel() {
    }

    public QueryModel(String selectFields) {
        this.selectFields = selectFields;
    }

    protected Object formatValue(Object value) {
        if (value != null && value.getClass() == java.util.Date.class) {
            return new java.sql.Timestamp(((Date) value).getTime());
        } else {
            return value;
        }
    }

    public QueryModel(String fieldName, Object value) {
        addEq(fieldName, value);
    }

    public void addEq(String fieldName, Object value) {
        addEq(fieldName, value, true);
    }

    public void addEq(String fieldName, Object value, boolean ignoreNull) {
        if (value == null || (value.equals("") && ignoreNull)) {
            Condition cnd = new Condition(fieldName, Condition.Type.EQUAL, null);
            cnds.add(cnd);
            condition += " AND " + fieldName + " IS NULL";
        } else {
            Condition cnd = new Condition(fieldName, Condition.Type.EQUAL, value);
            cnds.add(cnd);
            condition += " AND " + fieldName + "=?";
            params.add(formatValue(value));
        }
    }

    /**
     * 为查询条件追加左括号
     *
     * @author hansai
     * @date 2019-08-14 14:46
     */
    public void appendLeftParenthesis() {
        condition += " ( ";
    }

    /**
     * 为查询条件追加右括号
     *
     * @author hansai
     * @date 2019-08-14 14:46
     */
    public void appendRightParenthesis() {
        condition += " ) ";
    }

    /**
     * 为查询条件追加 or
     *
     * @author hansai
     * @date 2019-08-08 11:54
     */
    public void appendOr() {
        condition += " OR ";
    }

    /**
     * 调整动态查询条件
     *
     * @author hansai
     * @date 2019-08-08 14:37
     */
    public void adjustmentDynamicCondition() {
        // 1: ( and 替换为 and (
        // 2: or and 替换为 or
        condition = condition.replaceAll("\\s+\\(\\s+(?i)and\\s+", " AND ( ").replaceAll("\\s+(?i)or\\s+(?i)and\\s+", " OR ")
                .replaceAll("\\s+\\(\\s+(?i)and\\s+", " AND ( ");
        if (condition.endsWith("OR ")) {
            condition = condition.substring(0, condition.lastIndexOf("OR "));
        }
    }

    public <T> void addEq(Property<T, ?> property, Object value) {
        addEq(QueryManager.getFunctionName(property), value);
    }

    public void addUnEq(String fieldName, Object value) {
        addUnEq(fieldName, value, true);
    }

    public void addUnEq(String fieldName, Object value, boolean ignoreNull) {
        if (value == null || (value.equals("") && ignoreNull)) {
            Condition cnd = new Condition(fieldName, Condition.Type.NOT_EQUAL, null);
            cnds.add(cnd);
            condition += " AND " + fieldName + " IS NOT NULL";
        } else {
            Condition cnd = new Condition(fieldName, Condition.Type.NOT_EQUAL, value);
            cnds.add(cnd);
            condition += " AND " + fieldName + "!=?";
            params.add(formatValue(value));
        }
    }

    public <T> void addUnEq(Property<T, ?> property, Object value) {
        addUnEq(QueryManager.getFunctionName(property), value);
    }

    // 大于
    public void addGt(String fieldName, Object value) {
        Condition cnd = new Condition(fieldName, Condition.Type.GT, value);
        cnds.add(cnd);
        condition += " AND " + fieldName + ">?";
        params.add(formatValue(value));
    }

    public <T> void addGt(Property<T, ?> property, Object value) {
        addGt(QueryManager.getFunctionName(property), value);
    }

    public void addGe(String fieldName, Object value) {
        Condition cnd = new Condition(fieldName, Condition.Type.GE, value);
        cnds.add(cnd);
        condition += " AND " + fieldName + ">=?";
        params.add(formatValue(value));
    }

    public <T> void addGe(Property<T, ?> property, Object value) {
        addGe(QueryManager.getFunctionName(property), value);
    }

    // 小于
    public void addLt(String fieldName, Object value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LT, value);
        cnds.add(cnd);
        condition += " AND " + fieldName + "<?";
        params.add(formatValue(value));
    }

    public <T> void addLt(Property<T, ?> property, Object value) {
        addLt(QueryManager.getFunctionName(property), value);
    }

    public void addLe(String fieldName, Object value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LE, value);
        cnds.add(cnd);
        condition += " AND " + fieldName + "<=?";
        params.add(formatValue(value));
    }

    public <T> void addLe(Property<T, ?> property, Object value) {
        addLe(QueryManager.getFunctionName(property), value);
    }

    public void addLeftLike(String fieldName, String value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LIKE_LEFT, value);
        cnds.add(cnd);
        condition += " AND " + fieldName + " LIKE ?";
        params.add(value + "%");
    }

    public <T> void addLeftLike(Property<T, ?> property, String value) {
        addLeftLike(QueryManager.getFunctionName(property), value);
    }

    public void addRightLike(String fieldName, String value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LIKE_RIGHT, value);
        cnds.add(cnd);
        condition += " AND " + fieldName + " LIKE ?";
        params.add("%" + value);
    }

    public <T> void addRightLike(Property<T, ?> property, String value) {
        addRightLike(QueryManager.getFunctionName(property), value);
    }

    public void addLike(String fieldName, String value) {
        Condition cnd = new Condition(fieldName, Condition.Type.LIKE, value);
        cnds.add(cnd);
        condition += " AND " + fieldName + " LIKE ?";
        params.add("%" + value + "%");
    }

    public <T> void addLike(Property<T, ?> property, String value) {
        addLike(QueryManager.getFunctionName(property), value);
    }

    public void addRegion(String fieldName, Object value1, Object value2) {
        List<Object> list = new ArrayList<>();
        list.add(value1);
        list.add(value2);
        Condition cnd = new Condition(fieldName, Condition.Type.BETWEEN, list);
        cnds.add(cnd);
        condition += " AND " + fieldName + " BETWEEN ? AND ?"; // >= && <=
        params.add(formatValue(value1));
        params.add(formatValue(value2));
    }

    public <T> void addRegion(Property<T, ?> property, Object value1, Object value2) {
        addRegion(QueryManager.getFunctionName(property), value1, value2);
    }

    public void addInCondition(String fieldName, String subCondition, Object... sqlParams) {
        Condition cnd = new Condition(fieldName, Condition.Type.IN_STR, subCondition, sqlParams);
        cnds.add(cnd);
        condition += " AND " + fieldName + " IN (" + subCondition + ")";
        params.addAll(Arrays.asList(sqlParams));
    }

    public <T> void addInCondition(Property<T, ?> property, String subCondition, Object... sqlParams) {
        addInCondition(QueryManager.getFunctionName(property), subCondition, sqlParams);
    }

    public void addNotInCondition(String fieldName, String subCondition, Object... sqlParams) {
        Condition cnd = new Condition(fieldName, Condition.Type.NOT_IN_STR, subCondition, sqlParams);
        cnds.add(cnd);
        condition += " AND " + fieldName + " NOT IN (" + subCondition + ")";
        params.addAll(Arrays.asList(sqlParams));
    }

    public <T> void addNotInCondition(Property<T, ?> property, String subCondition, Object... sqlParams) {
        addNotInCondition(QueryManager.getFunctionName(property), subCondition, sqlParams);
    }

    public void addExistsCondition(String subCondition, Object... sqlParams) {
        Condition cnd = new Condition("", Condition.Type.EXISTS, subCondition, sqlParams);
        cnds.add(cnd);
        condition += " AND EXISTS (" + subCondition + ")";
        params.addAll(Arrays.asList(sqlParams));
    }

    public void addNotExistsCondition(String subCondition, Object... sqlParams) {
        Condition cnd = new Condition("", Condition.Type.NOT_EXISTS, subCondition, sqlParams);
        cnds.add(cnd);
        condition += " AND NOT EXISTS (" + subCondition + ")";
        params.addAll(Arrays.asList(sqlParams));
    }

    public void addInSet(String fieldName, Object[] values) {
        addInSet(fieldName, values, true);
    }

    public <T> void addInSet(Property<T, ?> property, Object[] values) {
        addInSet(QueryManager.getFunctionName(property), values);
    }

    // isContained 是否为包含，重新提交张和祥修改
    public void addInSet(String fieldName, Object[] values, boolean isContained) {
        Condition cnd = new Condition(fieldName, isContained ? Condition.Type.IN_SET : Condition.Type.NOT_IN_SET, values);
        cnds.add(cnd);
        condition += " AND " + getInStr(fieldName, values, isContained);
    }

    private String getInStr(String fieldName, Object[] values, boolean isContained) {
        // 张和祥：添加values数量可能大于1000的处理
        StringBuffer sb = new StringBuffer();
        if (values != null) {

            if (values.length > 1000) { // 不建议使用
                log.warn("   in 参数超过1000个，不建议如此使用，请检查sql语句是否可以优化(>﹏<)！(>﹏<)！(>﹏<)！(>﹏<)！(>﹏<)！");
//                String str = "";
                StringBuilder strSb = new StringBuilder("");
                int iCount = values.length % 1000 == 0 ? values.length / 1000 : (values.length / 1000 + 1);
                for (int i = 0; i < iCount; i++) {
//                    String strTemp = "";
                    StringBuilder strTempSb = new StringBuilder("");
                    int iCountTemp = (i == iCount - 1) ? values.length : 1000 * (i + 1);
                    for (int j = (0 + 1000 * i); j < iCountTemp; j++) {
                        Object value = values[j];
//                        strTemp += ",'" + value + "'";
                        strTempSb.append(",'").append(value).append("'");
                    }
                    if (isContained) {
//                        str += " OR " + fieldName + " IN (" + strTemp.substring(1) + ")";
                        strSb.append(" OR ").append(fieldName).append(" IN (").append(strTempSb.toString().substring(1)).append(")");
                    } else {
//                        str += " AND " + fieldName + " NOT IN (" + strTemp.substring(1) + ")";
                        strSb.append(" AND ").append(fieldName).append(" NOT IN (").append(strTempSb.toString().substring(1)).append(")");
                    }
                }
                sb.append(" (" + strSb.toString().substring(4) + ")");
            } else {
//                String str = "";
                StringBuilder strSb = new StringBuilder("");
                for (Object value : values) {
//                    str += ",'" + value + "'";
                    strSb.append(",'").append(value).append("'");
                }
                // 当values.length==0是防止substring溢出
//                str = str.length() == 0 ? ",''" : str; // TODO 有问题吧？吕凯标注
                String str = strSb.length() == 0 ? ",''" : strSb.toString();
                if (isContained) {
                    sb.append(fieldName + " IN (" + str.substring(1) + ")");
                } else {
                    sb.append(fieldName + " NOT IN (" + str.substring(1) + ")");
                }
            }
        }
        return sb.toString();
    }

    public void addInSet(String fieldName, Set<?> values) {
        addInSet(fieldName, values, true);
    }

    public <T> void addInSet(Property<T, ?> property, Set<?> values) {
        addInSet(QueryManager.getFunctionName(property), values);
    }

    public void addInSet(String fieldName, Set<?> values, boolean isContained) {
        addInSet(fieldName, values.toArray(), isContained);
    }

    public <T> void addInSet(Property<T, ?> property, Set<?> values, boolean isContained) {
        addInSet(QueryManager.getFunctionName(property), values, isContained);
    }

    public void addInSet(String fieldName, QueryModel queryModel, Class<?> clazz) {
        addInSet(fieldName, queryModel, clazz, true);
    }

    public <T> void addInSet(Property<T, ?> property, QueryModel queryModel, Class<?> clazz) {
        addInSet(QueryManager.getFunctionName(property), queryModel, clazz, true);
    }

    public <T> void addInSet(Property<T, ?> property, QueryModel queryModel, Class<?> clazz, boolean isContained) {
        addInSet(QueryManager.getFunctionName(property), queryModel, clazz, isContained);
    }

    /**
     * 
     * 通过queryModel进行in查询
     * 
     * @Title addInSet
     * @author 武杨
     * @date 2020年11月25日 上午10:53:50
     * @param <T>
     * @param fieldName
     *            被对比字段
     * @param queryModel
     * @param clazz
     *            in中的tableName
     * @param isContained
     *            void
     */
    public <T> void addInSet(String fieldName, QueryModel queryModel, Class<T> clazz, boolean isContained) {
        if ("*".equals(queryModel.getSelectFields()) || queryModel.getSelectFields().contains(",")) {
            log.warn("有且只能有一个参数");
            return;
        }
        try {
            String inStr = "SELECT " + queryModel.getSelectFields() + " FROM " + TableNameUtil.getTableName(clazz) + " "
                    + queryModel.getNoOrderQueryStr(null);
            /*
             * Object[] whereQueryParams = queryModel.getParams(); if (whereQueryParams != null && whereQueryParams.length > 0) { // 参数存在
             * this.params.addAll(Arrays.asList(whereQueryParams)); } Condition cnd = new Condition(fieldName, isContained ?
             * Condition.Type.IN_SET : Condition.Type.NOT_IN_SET, inStr); cnds.add(cnd); condition += " AND " + fieldName + (isContained ?
             * "" : " NOT") + " IN ( " + inStr + " )";
             */

            if (isContained) {
                addInCondition(fieldName, inStr, queryModel.getParams());
            } else {
                addNotInCondition(fieldName, inStr, queryModel.getParams());
            }

        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 添加多对多的主键查询,少量数据时使用
     * 
     * @Title addM2MIdLink
     * @author 吕凯
     * @date 2019年8月14日 上午11:13:39
     * @param clazz
     * @param property
     * @param value
     *            关联对象relationTo的值 void
     */
    public <T> void addM2MIdLink(Class<T> clazz, Property<T, ?> property, Object value) {
        addM2MIdLink(clazz, property, value, null);
    }

    /**
     * 
     * 添加多对多的主键查询(in查询),少量数据时使用
     * 
     * @Title addM2MIdLink
     * @author 吕凯
     * @date 2019年8月19日 下午3:18:27
     * @param clazz
     * @param property
     * @param value
     * @param queryModel
     *            void
     */
    public <T> void addM2MIdLink(Class<T> clazz, Property<T, ?> property, Object value, QueryModel queryModel) {
        Field field;
        try {
            field = AnnotationUtil.getField(clazz, FunctionUtil.getFieldName(property));
            if (field.isAnnotationPresent(Many2Many.class)) {
                Many2Many manyAnno = field.getAnnotation(Many2Many.class);
                String condition = "SELECT " + manyAnno.relationFrom() + " FROM " + TableNameUtil.getTableName(manyAnno.relation())
                        + " WHERE " + manyAnno.relationTo() + "=? ";
                List<Object> paramList = new ArrayList<>();
                paramList.add(value);
                if (queryModel != null) {
                    String whereCnd = queryModel.getNoOrderQueryStrCondition(null);
                    if (StringUtils.isNotEmpty(whereCnd)) {
                        condition += "AND" + whereCnd;
                        Object[] whereQueryParams = queryModel.getParams();
                        if (whereQueryParams != null && whereQueryParams.length > 0) { // 参数存在
                            paramList.addAll(Arrays.asList(whereQueryParams));
                        }
                    }
                }
//                condition += ") ";

                addInCondition(manyAnno.from(), condition, paramList.toArray());
            }
        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 
     * 添加多对多的主键查询(exists查询),注意表的别名
     * 
     * @Title addM2MIdLinkByExists
     * @author 吕凯
     * @date 2019年8月19日 下午3:19:02
     * @param clazz
     * @param property
     * @param value
     * @param tableNameAlias
     *            void
     */
    public <T> void addM2MIdLinkByExists(Class<T> clazz, Property<T, ?> property, Object value, String tableNameAlias) {
        Field field;
        try {
            field = AnnotationUtil.getField(clazz, FunctionUtil.getFieldName(property));
            if (field.isAnnotationPresent(Many2Many.class)) {
                Many2Many manyAnno = field.getAnnotation(Many2Many.class);
                String condition = " SELECT " + manyAnno.relationFrom() + " FROM " + TableNameUtil.getTableName(manyAnno.relation())
                        + " tpl WHERE tpl." + manyAnno.relationFrom() + "=";
                if (StringUtils.isNotBlank(tableNameAlias)) {
                    condition += tableNameAlias + ".";
                } else {
                    condition += TableNameUtil.getTableName(clazz) + ".";
                }
                condition += manyAnno.from() + " AND " + manyAnno.relationTo() + "=? ";

//                this.condition += condition;
//                this.params.add(value);

                addExistsCondition(condition, value);
            }
        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 
     * 
     * 添加多对多的主键查询(exists查询),如果表的别名如果有误建议使用addM2MIdLinkByExists(Class<T> clazz, Property<T, ?> property, Object value, String
     * tableNameAlias)方法
     * 
     * @Title addM2MIdLinkByExists
     * @author 吕凯
     * @date 2019年9月19日 下午4:02:49
     * @param clazz
     * @param property
     * @param value
     *            void
     */
    public <T> void addM2MIdLinkByExists(Class<T> clazz, Property<T, ?> property, Object value) {
        addM2MIdLinkByExists(clazz, property, value, null);
    }

    public static void main(String[] args) {
        String ss = " and a= '123' and 1=1 and b='1'";
        QueryModel queryModel = new QueryModel();
        queryModel.addCondition(ss);
        queryModel.addEq("ff", "12121");
        queryModel.setJoinType(JoinType.INNER_JOIN);
        QueryModel copy;
        QueryModel copy1;
        try {
            copy = (QueryModel) queryModel.clone();
            copy1 = queryModel.copy();
            System.out.println("00==" + copy);
            String ss1 = " and b like 'test%'";
            queryModel.addCondition(ss1);
            queryModel.setJoinType(JoinType.LEFT_OUTER_JOIN);
            System.out.println("00==" + copy);
            System.out.println("00==" + copy1);
            System.out.println("11==" + queryModel);
        } catch (CloneNotSupportedException e) {
            log.error("", e);
        }
    }

    public void addCondition(String condition, Object... values) {
        Condition cnd = new Condition("", Condition.Type.SQL_STR, condition, values);
        cnds.add(cnd);
        this.condition += " AND " + condition;
        if (values.length > 0) {
            for (Object v : values) {
                this.params.add(v);
            }
        }
    }

    public void addMultiCondition(boolean isOr, QueryModel... queryModels) {
        if (isOr) {
            addOrMultiCondition(queryModels);
        } else {
            addAndMultiCondition(queryModels);
        }
    }

    public void addAndMultiCondition(QueryModel... queryModels) {
        for (QueryModel tempQueryModel : queryModels) {
            String temp = tempQueryModel.getCondition();
            if (temp != null && !temp.isEmpty()) {
                condition += " AND " + temp;
                params.addAll(Arrays.asList(tempQueryModel.getParams()));
            }
        }
    }

    public void addOrMultiCondition(QueryModel... queryModels) {
//        String tempCondition = "";
        StringBuilder tempConditionSb = new StringBuilder("");
        for (QueryModel tempQueryModel : queryModels) {
            String temp = tempQueryModel.getCondition();
            if (temp != null && !temp.isEmpty()) {
//                tempCondition += " OR (" + temp + ")";
                tempConditionSb.append(" OR (").append(temp).append(")");
                params.addAll(Arrays.asList(tempQueryModel.getParams()));
            }
        }
        condition += " AND (" + tempConditionSb.toString().substring(4) + ")";
    }

    /**
     * 设置排序规则，如果之前设置过，该方法会重置，如果要追加使用addOrder方法
     * 
     * @Title setOrder
     * @author 吕凯
     * @date 2020年6月5日 下午6:13:58
     * @param fieldName
     * @param isDesc
     *            void
     */
    public void setOrder(String fieldName, boolean isDesc) {
        order = "";
        orders.clear();
        addOrder(fieldName, isDesc);
        /*
         * order = " ORDER BY " + fieldName; if (isDesc) { order += " DESC"; }
         */
    }

    /**
     * 追加排序规则
     * 
     * @Title addOrder
     * @author 吕凯
     * @date 2020年6月2日 下午4:21:48
     * @param fieldName
     * @param isDesc
     *            void
     */
    public void addOrder(String fieldName, boolean isDesc) {
        if (fieldName.contains(",")) {
            log.warn("检测到排序字段名中使用了多个字符串，建议使用setOrder设置主排序字段addOrder增加副排序字段");
            Arrays.asList(fieldName.split(",")).forEach(order -> {
                String orderStr = order.trim().toLowerCase();
                boolean orderIsDesc = isDesc;
                if (orderStr.contains("desc")) {
                    orderIsDesc = true;
                    orderStr = StringUtils.substringBefore(orderStr, "desc");
                } else if (orderStr.contains("asc")) {
                    orderIsDesc = false;
                    orderStr = StringUtils.substringBefore(orderStr, "asc");
                }
                orderStr = orderStr.trim();
                Order orderTemp = new Order(orderStr, orderIsDesc);
                orders.add(orderTemp);
            });
        } else {
            Order order = new Order(fieldName, isDesc);
            orders.add(order);
        }
    }

    public <T> void addOrder(Property<T, ?> property, boolean isDesc) {
        addOrder(QueryManager.getFunctionName(property), isDesc);
    }

    public <T> void setOrder(Property<T, ?> property, boolean isDesc) {
        setOrder(QueryManager.getFunctionName(property), isDesc);
    }

    private String getCondition() {
        if (condition.isEmpty()) {
            return "";
        }
        return condition.substring(4);
    }

    /**
     * 设置排序规则，如果之前设置过，该方法会重置，如果要追加使用addOrder方法
     * 
     * @Title setOrder
     * @author 吕凯
     * @date 2020年6月5日 下午6:13:58
     * @param fieldName
     * @param isDesc
     *            void
     */
    public void setGroupBy(String fieldName) {
        groupBys.clear();
        addGroupBy(fieldName);
    }

    public <T> void setGroupBy(Property<T, ?> property) {
        setGroupBy(QueryManager.getFunctionName(property));
    }

    /**
     * 
     * 追加分组规则
     * 
     * @Title addGroupBy
     * @author 吕凯
     * @date 2022年7月19日 下午12:09:21
     * @param fieldName
     *            void
     */
    public void addGroupBy(String fieldName) {
        groupBys.add(fieldName);
    }

    public <T> void addGroupBy(Property<T, ?> property) {
        addGroupBy(QueryManager.getFunctionName(property));
    }

    /**
     * 此方法将被getNoOrderQueryStr(String tableAlias) 替代，下个版本删除
     * 
     * @Title getNoOrderQueryStr
     * @author 吕凯
     * @date 2019年8月16日 下午6:51:41
     * @return String
     */
    @Deprecated
    public String getNoOrderQueryStr() {
        if (condition.isEmpty()) {
            return "";
        }
        return " WHERE" + condition.substring(4) + getGroupBy(null);
    }

    public String getNoOrderQueryStr(String tableAlias) {
        if (condition.isEmpty()) {
            return "";
        }
        return " WHERE" + getNoOrderQueryStrCondition(tableAlias);
    }

    /**
     * 此方法将被getNoOrderQueryStr(String tableAlias) 替代，下个版本删除
     * 
     * @Title getOrderQueryStr
     * @author 吕凯
     * @date 2019年8月16日 下午6:51:41
     * @return String
     */
    @Deprecated
    public String getOrderQueryStr() {
        return getNoOrderQueryStr() + getOrder(null);
    }

    public String getOrderQueryStr(String tableAlias) {
        return getNoOrderQueryStr(tableAlias) + getOrder(null);
    }

    /**
     * 获取排序字符串
     * 
     * @Title getOrder
     * @author 吕凯
     * @date 2014年7月19日 上午11:47:02
     * @param tableAlias
     * @return String
     */
    public String getOrder(String tableAlias) {
        if (StringUtils.isEmpty(order)) {
            StringBuffer sb = new StringBuffer();
            boolean isFirst = true;
            for (Order order : orders) {
                if (!isFirst) {
                    sb.append(",");
                }
                if (!order.getColumn().contains(".") && StringUtils.isNotEmpty(tableAlias)) { // 不包含.
                    sb.append(tableAlias).append(".");
                }
                sb.append(order.getColumn()).append(order.getIsDesc() ? " DESC" : "");
                isFirst = false;
            }
            if (sb.length() > 0) {
                sb.insert(0, " ORDER BY ");
            }
            // order += sb.toString(); //不赋值给order，防止取值时更改order的值
            return sb.toString();
        }
        return order;
    }

    /**
     * 获取分组条件字符串（暂未使用）
     * 
     * @Title getGroupBy
     * @author 吕凯
     * @date 2022年7月19日 上午11:48:22
     * @param tableAlias
     * @return String
     */
    public String getGroupBy(String tableAlias) {
        if (ListUtils.isNotEmpty(groupBys)) {
            StringBuffer sb = new StringBuffer();
            boolean isFirst = true;
            for (String groupByStr : groupBys) {
                if (!isFirst) {
                    sb.append(",");
                }
                if (!groupByStr.contains(".") && StringUtils.isNotEmpty(tableAlias)) { // 不包含.则添加表名
                    sb.append(tableAlias).append(".");
                }
                sb.append(groupByStr);
                isFirst = false;
            }
            if (sb.length() > 0) {
                sb.insert(0, " GROUP BY ");
            }
            // groupBy += sb.toString(); //不赋值给groupBy，防止取值时更改groupBy的值
            return sb.toString();
        }
        return "";
    }

    public Object[] getParams() {
        return params.toArray();
    }

    public String getSelectFields() {
        return selectFields;
    }

    public void setSelectFields(String selectFields) {
        this.selectFields = selectFields;
    }

    public <T> void setSelectFields(Property<T, ?> property) {
        setSelectFields(QueryManager.getFunctionName(property));
    }

    /**
     * 添加选择属性，支持安全输出
     * 
     * @Title addSelectFields
     * @author 吕凯
     * @date 2022年7月19日 上午11:57:47
     * @param <T>
     * @param property
     *            void
     */
    public <T> void addSelectFields(Property<T, ?> property) {
        if (StringUtils.isNotEmpty(this.selectFields)) {
            this.selectFields += ",";
        } else {
            this.selectFields = "";
        }
        this.selectFields += QueryManager.getFunctionName(property);
    }

    /**
     * 添加查询添加sql,以and开头,使用getNoOrderQueryStrCondition(String tableAlias)替代，下次升级将删除此方法
     * 
     * @return
     * @author 玄承勇
     * @date 2014-6-30 上午9:35:30
     */
    @Deprecated
    public String getNoOrderQueryStrCondition() {
        if (condition.isEmpty()) {
            return "";
        }
        return " AND " + condition.substring(4);
    }

    public String getNoOrderQueryStrCondition(String tableAlias) {
        StringBuffer sb = new StringBuffer();
        cnds.stream()/* .filter(cnd -> cnd.getQueryType() != Cnd.Type.ORDER) */.forEach(cnd -> {
            String colunmName = cnd.getColumn();
            sb.append(" AND ");
            if (StringUtils.isNotEmpty(colunmName)) {
                if (StringUtils.isNotEmpty(tableAlias)) {
//                    sb.append(tableAlias).append(".");
                    colunmName = tableAlias + "." + colunmName;
                }
                if (cnd.getQueryType() != Condition.Type.EXISTS && cnd.getQueryType() != Condition.Type.NOT_EXISTS
                        && cnd.getQueryType() != Condition.Type.SQL_STR && cnd.getQueryType() != Condition.Type.IN_SET
                        && cnd.getQueryType() != Condition.Type.NOT_IN_SET) { // exists需要单独处理
                    sb.append(colunmName);
                }
            }
            // 每个条件前面加空格，后面不加
            if (cnd.getQueryType() == Condition.Type.EQUAL) {
                if (cnd.getValues() == null) {
                    sb.append(" IS NULL");
                } else {
                    sb.append(" = ").append("?");
                }
            } else if (cnd.getQueryType() == Condition.Type.NOT_EQUAL) {
                if (cnd.getValues() == null) {
                    sb.append(" IS NOT NULL");
                } else {
                    sb.append(" != ").append("?");
                }
            } else if (cnd.getQueryType() == Condition.Type.GT) {
                sb.append(" > ").append("?");
            } else if (cnd.getQueryType() == Condition.Type.GE) {
                sb.append(" >= ").append("?");
            } else if (cnd.getQueryType() == Condition.Type.LT) {
                sb.append(" < ").append("?");
            } else if (cnd.getQueryType() == Condition.Type.LE) {
                sb.append(" <= ").append("?");
            } else if (cnd.getQueryType() == Condition.Type.LIKE || cnd.getQueryType() == Condition.Type.LIKE_LEFT
                    || cnd.getQueryType() == Condition.Type.LIKE_RIGHT) {
                sb.append(" LIKE ").append("?");
            } else if (cnd.getQueryType() == Condition.Type.BETWEEN) {
                sb.append(" BETWEEN ").append("?").append(" and ").append("?");
            } else if (cnd.getQueryType() == Condition.Type.IN_STR) {
                sb.append(" IN ( ").append(cnd.getValues()).append(" )");
            } else if (cnd.getQueryType() == Condition.Type.NOT_IN_STR) {
                sb.append(" NOT IN ( ").append(cnd.getValues()).append(" )");
            } else if (cnd.getQueryType() == Condition.Type.IN_SET) {
                sb.append(getInStr(colunmName, (Object[]) cnd.getValues(), true));
            } else if (cnd.getQueryType() == Condition.Type.NOT_IN_SET) {
                sb.append(getInStr(colunmName, (Object[]) cnd.getValues(), false));
            } else if (cnd.getQueryType() == Condition.Type.EXISTS) {
                sb.append(" EXISTS (").append(cnd.getValues()).append(")");
            } else if (cnd.getQueryType() == Condition.Type.NOT_EXISTS) {
                sb.append(" NOT EXISTS (").append(cnd.getValues()).append(")");
            } else if (cnd.getQueryType() == Condition.Type.SQL_STR && ObjectUtils.isNotEmpty(cnd.getValues())) { // 排除空对象
                sb.append(cnd.getValues());
            }
        });
        String queryStr = sb.toString();
        if (queryStr.startsWith(" AND ")) { // 如果以AND 开头，表示主表没有查询条件，需要将第一个AND替换掉
            queryStr = queryStr.replaceFirst(" AND ", " ");
        }
        return queryStr;
    }

    public void addLimit(int value) {
        condition += " LIMIT " + value;
    }

    /**
     * 重新clone方法
     * 
     * @Title clone
     * @author xx
     * @date 2013年7月26日 下午1:46:40
     * @return
     * @throws CloneNotSupportedException
     * @see java.lang.Object#clone()
     */
    @Override
    public Object clone() throws CloneNotSupportedException {

        QueryModel cloneObj = null;
        try {
            cloneObj = (QueryModel) super.clone();
            // 处理集合字段
            if (this.queryLinkFields != null) {
                cloneObj.queryLinkFields = new ArrayList<>(this.queryLinkFields); // 查询哪些级联对象，如果queryLink为true此项不设置默认查询model中配置了@Link注解的
            }
            if (this.params != null) {
                cloneObj.params = new ArrayList<>(this.params); // 指针不变，所以new一下
            }
            if (this.cnds != null) {
                cloneObj.cnds = new ArrayList<>(this.cnds);// 条件
            }
            if (this.orders != null) {
                cloneObj.orders = new ArrayList<>(this.orders);// 排序
            }
        } catch (CloneNotSupportedException e) {
            log.error("", e);
        }
        return cloneObj;
    }

    public Boolean getQueryLink() {
        return queryLink;
    }

    public void setQueryLink(Boolean queryLink) {
        this.queryLink = queryLink;
    }

    public List<Property<?, ?>> getQueryLinkFields() {
        return queryLinkFields;
    }

    /**
     * 添加参数
     * 
     * @Title addQueryField
     * @author 吕凯
     * @date 2019年7月26日 下午1:47:09
     * @param property
     *            void
     */
    public <T> void addQueryField(Property<T, ?> property) {
        if (queryLinkFields == null) {
            queryLinkFields = new ArrayList<>();
        }
        if (!queryLinkFields.contains(property)) {
            queryLinkFields.add(property);
        }
    }

    public <T> void clearQueryField() {
        if (queryLinkFields != null) {
            queryLinkFields.clear();
        }
    }

    public QueryModel copy() {
        QueryModel newObj = new QueryModel();
        try {
            newObj = (QueryModel) this.clone();
        } catch (CloneNotSupportedException e) {
            log.error("", e);
        }

        return newObj;
    }

//    public static void main(String[] args) {
//        QueryModel queryModel = new QueryModel();
//        queryModel.addEq(QueryModel.class, QueryModel::getCondition, 1); //
//    }

}
